using System;
using System.Collections.Generic;
using System.Text;

namespace GuavaData
{
    public class GSeedFrame : Object
    {
        public Guid g;
        public string form;
        public List<string> controls;

        public GSeedFrame()
        {
            controls = new List<string>();
        }

        public GSeedFrame(Guid g, string form)
            : this()
        {
            this.g = g;
            this.form = form;
        }

        public List<string> ToList()
        {
            List<string> ls = new List<string>();
            ls.Add(form);
            foreach (string s in controls) ls.Add(s);
            return ls;
        }

        public override string ToString()
        {
            return String.Concat(g.ToString(), ":", form, ":", String.Join("/", controls.ToArray()));
        }

        public static GSeedFrame FromString(string s)
        {
            List<string> ls = new List<string>(s.Split(':'));

            // First element is guid, second is form
            GSeedFrame gsfTemp = new GSeedFrame(new Guid(ls[0]), ls[1]);

            // Third element is list of controls concatenated with /
            gsfTemp.controls = new List<string>(ls[2].Split('/'));

            return gsfTemp;
        }
    }

    public class GSeed : List<GSeedFrame>
    {
        public string root;
        int level;
        public string source;
        public string catalog;

        public GSeed(string root, string source, string catalog)
            : base()
        {
            this.level = 0;
            this.root = root;
            this.source = source;
            this.catalog = catalog;
        }

        public string formPath
        {
            get
            {
                string sTemp = "";
                Action<GSeedFrame> a = new Action<GSeedFrame>(delegate(GSeedFrame gs)
                {
                    sTemp = String.Concat(sTemp, "/", gs.form);
                });

                this.ForEach(a);
                return sTemp;
            }
        }

        public void Push(GSeedFrame gsf)
        {
            base.Add(gsf);
            level++;
        }

        public GSeedFrame Peek()
        {
            if (base.Count > 0) return base[base.Count - 1];
            else return null;
        }

        public GSeedFrame PeekAdvance()
        {
            if (NeedToAdvance) return base[level++];
            else return null;
        }

        public void Pop()
        {
            if (base.Count > 0) base.RemoveAt(base.Count - 1);
        }

        public bool NeedToAdvance
        {
            get
            {
                return (this.level < this.Count);
            }
        }

        public Guid NextId
        {
            get
            {
                if (this.level < this.Count) return base[level].g;
                return new Guid();
            }
        }

        public string NextForm
        {
            get
            {
                if (this.level < this.Count) return base[level].form;
                return null;
            }
        }

        public List<string> ToList()
        {
            List<string> ls = new List<string>();
            foreach (GSeedFrame gsf in base.ToArray()) ls.AddRange(gsf.ToList());
            return ls;
        }

        public override string ToString()
        {
            return String.Concat(root, "~", source, "~", catalog, "~", String.Join("~", base.ConvertAll(new Converter<GSeedFrame, string>(delegate(GSeedFrame gsTemp)
            {
                return gsTemp.ToString();
            }
                )).ToArray()));
        }

        public static GSeed FromString(string s)
        {
            string[] ls = s.Split('~');

            // Pull the first entry's form name as the root
            GSeed gs = new GSeed(ls[0], ls[1], ls[2]);

            // For all of the other entries, each corresponds to a frame, so build
            for (int i = 1; i < ls.Length; i++) gs.Add(GSeedFrame.FromString(ls[i]));

            // Return the result, noting that the level is still set to 0 because we used Add instead of Push
            return gs;
        }
    }
}